package world

import (
	"MetroBuilderGameJam/gameEngine/drawer"
	"MetroBuilderGameJam/gameEngine/geom"
	"github.com/stretchr/testify/require"
	"testing"
)

//func TestRailRoad_CorrectRoad(t *testing.T) {
//	a := &Station{}
//	b := &Station{}
//
//	rr := NewRailRoad(drawer.ColorGold)
//	err := rr.AddBranch(NewCompletedBranch(a, b, nil))
//	require.NoError(t, err)
//	rr.correctRoad()
//}

func TestRailRoad_AddBranch(t *testing.T) {
	a := NewStation(StationTypeCircle, geom.Point{X: 0, Y: 0})
	b := NewStation(StationTypeCircle, geom.Point{X: 1, Y: 1})
	c := NewStation(StationTypeCircle, geom.Point{X: 2, Y: 1})
	d := NewStation(StationTypeCircle, geom.Point{X: 3, Y: 0})

	rr := NewRailRoad(drawer.ColorGold)

	t.Run("add first branch success", func(t *testing.T) {
		cb, err := NewCompletedBranch(a, b, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.NoError(t, err)
		require.Equal(t, 1, rr.Count())
		require.False(t, rr.IsLoop())
		require.Same(t, cb, rr.GetFirstEdge().branch)
		require.Same(t, cb, rr.GetLastEdge().branch)
		require.Same(t, a, rr.GetFirstEdge().station)
		require.Same(t, b, rr.GetLastEdge().station)
		require.Same(t, rr, rr.branches[0].road)
	})

	t.Run("add second same branch error", func(t *testing.T) {
		cb, err := NewCompletedBranch(a, b, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.Error(t, err)
		require.Equal(t, 1, rr.Count())
	})

	t.Run("add second same branch reverse error", func(t *testing.T) {
		cb, err := NewCompletedBranch(b, a, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.Error(t, err)
		require.Equal(t, 1, rr.Count())
	})

	t.Run("add outside branch error", func(t *testing.T) {
		cb, err := NewCompletedBranch(d, c, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.Error(t, err)
		require.Equal(t, 1, rr.Count())
	})

	t.Run("add branch from begin error direction", func(t *testing.T) {
		cb, err := NewCompletedBranch(c, a, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.Error(t, err)
		require.Equal(t, 1, rr.Count())
	})

	t.Run("add branch from begin success", func(t *testing.T) {
		cb, err := NewCompletedBranch(a, c, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.NoError(t, err)
		require.Equal(t, 2, rr.Count())
		require.False(t, rr.IsLoop())
		require.Same(t, cb, rr.GetFirstEdge().branch)
		require.Same(t, rr.branches[1], rr.GetLastEdge().branch)
		require.Same(t, c, rr.GetFirstEdge().station)
		require.Same(t, b, rr.GetLastEdge().station)
		require.Same(t, c, rr.branches[0].from)
		require.Same(t, a, rr.branches[0].to)
		require.Same(t, a, rr.branches[1].from)
		require.Same(t, b, rr.branches[1].to)
	})

	t.Run("add branch from end success", func(t *testing.T) {
		cb, err := NewCompletedBranch(b, c, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.NoError(t, err)
		require.Equal(t, 3, rr.Count())
		require.True(t, rr.IsLoop())
		require.Same(t, cb, rr.GetLastEdge().branch)
		require.Same(t, rr.branches[2], rr.GetLastEdge().branch)
		require.Same(t, c, rr.GetFirstEdge().station)
		require.Same(t, c, rr.GetLastEdge().station)
		require.Same(t, c, rr.branches[0].from)
		require.Same(t, a, rr.branches[0].to)
		require.Same(t, a, rr.branches[1].from)
		require.Same(t, b, rr.branches[1].to)
	})

	t.Run("add new branch to loop line error", func(t *testing.T) {
		cb, err := NewCompletedBranch(c, d, rr)
		require.NoError(t, err)
		err = rr.AddBranch(cb)
		require.Error(t, err)
		require.Equal(t, 3, rr.Count())
		require.True(t, rr.IsLoop())
	})
}

func TestRailRoad_DisconnectStation_Lined(t *testing.T) {
	a := NewStation(StationTypeCircle, geom.Point{X: 0, Y: 0})
	b := NewStation(StationTypeCircle, geom.Point{X: 1, Y: 1})
	c := NewStation(StationTypeCircle, geom.Point{X: 2, Y: 1})

	rr := NewRailRoad(drawer.ColorGold)
	cb, err := NewCompletedBranch(a, b, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)

	t.Run("disconnect outside station error", func(t *testing.T) {
		_, err = rr.DisconnectStation(c)
		require.Error(t, err)
	})

	t.Run("disconnect first edge station success", func(t *testing.T) {
		_, err = rr.DisconnectStation(a)
		require.NoError(t, err)
		require.Equal(t, 0, rr.Count())
		require.Nil(t, rr.GetFirstEdge())
		require.Nil(t, rr.GetLastEdge())
	})

	cb, err = NewCompletedBranch(a, b, nil)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)

	t.Run("disconnect second edge station success", func(t *testing.T) {
		_, err = rr.DisconnectStation(b)
		require.NoError(t, err)
		require.Equal(t, 0, rr.Count())
	})

	cb, err = NewCompletedBranch(a, b, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)
	cb, err = NewCompletedBranch(b, c, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)

	t.Run("disconnect middle station success", func(t *testing.T) {
		_, err = rr.DisconnectStation(b)
		require.NoError(t, err)
		require.Equal(t, 1, rr.Count())
		require.Same(t, a, rr.branches[0].from)
		require.Same(t, c, rr.branches[0].to)
	})

}

func TestRailRoad_DisconnectStation_Looped(t *testing.T) {
	a := NewStation(StationTypeCircle, geom.Point{X: 0, Y: 0})
	b := NewStation(StationTypeCircle, geom.Point{X: 1, Y: 1})
	c := NewStation(StationTypeCircle, geom.Point{X: 2, Y: 1})
	d := NewStation(StationTypeCircle, geom.Point{X: 3, Y: 0})

	rr := NewRailRoad(drawer.ColorGold)
	cb, err := NewCompletedBranch(a, b, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)
	cb, err = NewCompletedBranch(b, c, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)
	cb, err = NewCompletedBranch(a, c, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)
	require.True(t, rr.IsLoop())

	t.Run("disconnect station success", func(t *testing.T) {
		_, err := rr.DisconnectStation(c)
		require.NoError(t, err)
		require.Equal(t, 2, rr.Count())
		require.Same(t, a, rr.branches[0].from)
		require.Same(t, b, rr.branches[0].to)
		require.Same(t, b, rr.branches[1].from)
		require.Same(t, c, rr.branches[1].to)
		require.False(t, rr.IsLoop())
	})

	cb, err = NewCompletedBranch(a, d, rr)
	require.NoError(t, err)
	err = rr.AddBranch(cb)
	require.NoError(t, err)
}

func TestRailRoad_ChangeCompletedBranch(t *testing.T) {
	a := NewStation(StationTypeCircle, geom.Point{X: 0, Y: 0})
	b := NewStation(StationTypeCircle, geom.Point{X: 1, Y: 1})
	c := NewStation(StationTypeCircle, geom.Point{X: 2, Y: 1})

	rr := NewRailRoad(drawer.ColorGold)
	branch, err := NewCompletedBranch(a, b, rr)
	require.NoError(t, err)
	err = rr.AddBranch(branch)
	require.NoError(t, err)

	t.Run("change alone branch error", func(t *testing.T) {
		err = rr.AddStationToCompletedBranch(rr.branches[0], a)
		require.Error(t, err)
		err = rr.AddStationToCompletedBranch(rr.branches[0], b)
		require.Error(t, err)
		require.Equal(t, 1, rr.Count())
	})
	t.Run("change alone branch success", func(t *testing.T) {
		err = rr.AddStationToCompletedBranch(rr.branches[0], c)
		require.NoError(t, err)
		require.Equal(t, 2, rr.Count())
		require.Same(t, a, rr.branches[0].from)
		require.Same(t, c, rr.branches[0].to)
		require.Same(t, c, rr.branches[1].from)
		require.Same(t, b, rr.branches[1].to)
	})
}
